package context.environ;

import java.awt.Dimension;
import java.awt.Toolkit;
import math.vec2i;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;

public class Window
{
    
    private static Window singleton = new Window();
    
    public static Window get()
    {
        return Window.singleton;
    }
    
    private Window()
    {
    }
    
    
    public static final int MSAA_NONE = 0;
    public static final int MSAA_X1 = 1;
    public static final int MSAA_X2 = 2;
    public static final int MSAA_X4 = 4;
    public static final int MSAA_X8 = 8;
    public static final int MSAA_X16 = 16;
    
    private static final int BITS_PER_PIXEL = 32;
    private static final int BITS_FOR_ALPHA = 8;
    private static final int BITS_FOR_STENCIL = 8;
    private static final int BITS_FOR_DEPTH = 16;
    
    
    public boolean mIsFullscreen;
    
    public boolean mIsVSync;
    
    public int mLevelMSAA;
    
    public int mMaxFPS;
    
    public String mTitle;
    
    public vec2i mSize;
    
    public vec2i mScreenSize;
    
    public vec2i mWindowSize;
    
    private PixelFormat mPixelFormat;
    
    private DisplayMode mDisplayMode;
    
    public void onStart()
    {
        this.mIsFullscreen = false;
        this.mIsVSync = true;
        this.mLevelMSAA = 0;
        this.mMaxFPS = 300;
        this.mTitle = "Rigid Bodies";
        
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        this.mScreenSize = new vec2i(screen.width, screen.height);
        this.mWindowSize = new vec2i(800, 600);
        
        this.mSize = this.mWindowSize.copy();
        
        this.mPixelFormat = this.genPixelFormat(this.mLevelMSAA);
        this.mDisplayMode = this.genDisplayMode();
        
        this.initDisplay();
    }
    
    public void onTick()
    {
        
        if (this.mIsFullscreen != Display.isFullscreen())
        {
            if (this.mIsFullscreen)
            {
                this.mSize.set(this.mScreenSize);
            }
            else
            {
                this.mSize.set(this.mWindowSize);
            }
            
            this.mDisplayMode = this.genDisplayMode();
            this.initDisplay();
        }
        
        Display.update();
        Display.sync(this.mMaxFPS);
//        if (this.mSize.x != Display.getWidth() || this.mSize.y != Display.getHeight())
//        {
//            this.mSize.set(
//                Display.getWidth(), 
//                Display.getHeight()
//            );
//        }
//        // Need a vsync change operation
//        if (this.levelMSAA != this.pixelFormat.getSamples())
//        {
//            this.pixelFormat = this.genPixelFormat(this.levelMSAA);
//            this.initDisplay();
//        }
        if (!this.mTitle.equals(Display.getTitle()))
        {
            Display.setTitle(this.mTitle);
        }
    }
    
    public boolean isCloseRequested()
    {
        return Display.isCloseRequested();
    }
    
    public float aspectRatio()
    {
        float aspectRatio = ((float) this.mSize.x) / this.mSize.y;
        return aspectRatio;
    }
    
    public void onEnd()
    {
        Display.destroy();
        this.mIsFullscreen = false;
        this.mIsVSync = false;
        this.mLevelMSAA = Window.MSAA_NONE;
        this.mTitle = null;
        this.mSize = null;
    }
    
    
    
    private DisplayMode genDisplayMode()
    {
        DisplayMode[] displayModes = null;
        try
        {
            displayModes = Display.getAvailableDisplayModes();
        }
        catch (LWJGLException e)
        {
            System.err.println(e);
            System.exit(1);
        }
        DisplayMode testMode;
        for (int i = 0; i < displayModes.length; i++)
        {
            testMode = displayModes[i];
            boolean matchW = (this.mSize.x == testMode.getWidth());
            boolean matchH = (this.mSize.y == testMode.getHeight());
            boolean matchBPP = (Window.BITS_PER_PIXEL == testMode.getBitsPerPixel());
            boolean matchFS = (testMode.isFullscreenCapable() || !this.mIsFullscreen);
            if (matchW && matchH && matchBPP && matchFS)
            {
                return testMode;
            }
        }
        return null;
    }
    
    private PixelFormat genPixelFormat(int msaaSamples)
    {
        PixelFormat pixFormat = new PixelFormat()
            .withBitsPerPixel(Window.BITS_PER_PIXEL)
            .withAlphaBits(Window.BITS_FOR_ALPHA)
            .withStencilBits(Window.BITS_FOR_STENCIL)
            .withDepthBits(Window.BITS_FOR_DEPTH)
            .withSamples(msaaSamples)
            .withSRGB(true)
        ;
        return pixFormat;
    }
    
    private void initDisplay()
    {
        Display.destroy();
        try
        {
            Display.setTitle(this.mTitle);
            Display.setVSyncEnabled(this.mIsVSync);
            Display.setFullscreen(this.mIsFullscreen);
            Display.setResizable(false);
            Display.setDisplayMode(this.mDisplayMode);
            ContextAttribs contextAttribs = new ContextAttribs(3, 3)
                    .withProfileCore(true)
                    .withProfileCompatibility(true);
            Display.create(this.mPixelFormat, contextAttribs);
        }
        catch (LWJGLException e)
        {
            System.err.println(e);
            System.exit(1);
        }
    }
    
}
